﻿using Servo_Tool.entity;
using Servo_Tool.cache;
using Servo_Tool.constant;
using Servo_Tool.domain;
using System.Collections.Generic;
using System.Linq;

namespace Servo_Tool.utils
{
    public class ServoUtils
    {
        /// <summary>
        /// 初始化PLC_ITEM
        /// </summary>
        /// <param name="item"></param>
        public static void InitPlcItem(PlcItemEntity item)
        {
            //将每一个PLC_ITEM添加到缓存中
            string itemNo = item.ITEM_NO;
            if (string.IsNullOrEmpty(itemNo))
            {
                return;
            }
            GlobalCachePool.single_plcItem_dict.Add(itemNo, item);
            //如果信号点包含EVENT_NO,则绑定相关事件
            if (!string.IsNullOrEmpty(item.EVENT_NO))
            {
                BindEventByItem(item);
            }
        }

        /// <summary>
        /// 初始化MEM_ITEM
        /// </summary>
        /// <param name="item"></param>
        public static void InitMemItem(MemItemEntity item)
        {
            //将每一个PLC_ITEM添加到缓存中
            string itemNo = item.ITEM_NO;
            if (string.IsNullOrEmpty(itemNo))
            {
                return;
            }
            GlobalCachePool.single_memItem_dict.Add(itemNo, item);
        }

        /// <summary>
        /// 初始化PLC_UNIT
        /// </summary>
        /// <param name="read"></param>
        public static void InitPlcRead(PlcReadEntity read)
        {
            string readNo = read.READ_NO;
            //0.判断是否为空
            if (string.IsNullOrEmpty(readNo))
            {
                return;
            }
            //1.对扫描信息进行处理
            string unitNo = read.UNIT_NO;
            string startItemNo = read.START_ITEM;
            string endItemNo = read.END_ITEM;
            //2.获取所有PLC_ITEM信息
            List<PlcItemEntity> items = new List<PlcItemEntity>();
            if (GlobalCachePool.plcItems_dict.TryGetValue(unitNo, out items))
            {
                PlcItemEntity beginEntity = items.FirstOrDefault(item => startItemNo.Equals(item.ITEM_NO));

                PlcItemEntity endEntity = items.FirstOrDefault(item => endItemNo.Equals(item.ITEM_NO));

                if (beginEntity == null || endEntity == null)
                {
                    //起始点或结束点未配置
                    return;
                }
                //2.1.根据点信息进行处理
                int dbBlock_begin = beginEntity.DB_BLOCK;
                int dbBlock_end = endEntity.DB_BLOCK;
                if (dbBlock_begin != dbBlock_end)
                {
                    //起始点与结束点不在同一个块号中
                    return;
                }
                read.DB_BLOCK = dbBlock_begin;
                read.BEGIN_ADR = beginEntity.ITEM_ADR;
                read.END_ADR = endEntity.ITEM_ADR;
                //2.2.根据起始点与结束点计算信号点数量
                read.READ_LEN = endEntity.ITEM_ADR - beginEntity.ITEM_ADR + 1;
                //TODO-不同设备一次读取信号点的位数不同
            }
            GlobalCachePool.single_plcRead_dict.Add(readNo, read);
            GlobalCachePool.read_data_dict.Add(readNo, null);
            //将属于该READ的相关点信息搜集起来并绑定相关事件
            BindItemByRead(read);
        }

        public static void InitPlcEvent(PlcEventEntity eva)
        {
            //0.判断是否为空
            string eventNo = eva.EVENT_NO;
            if (string.IsNullOrEmpty(eventNo))
            {
                return;
            }
            //1.将事件写入缓存
            GlobalCachePool.single_plcEvent_dict.Add(eventNo, eva);
            //2.对其触发条件进行处理
            List<EquationLinks_EVENT> equationLinks = EquationUtils.Cons2EquationLinks(eva.EVENT_CONS);
            if (equationLinks != null && equationLinks.Count > 0)
            {
                GlobalCachePool.links_event_dict.Add(eventNo, equationLinks);
            }
            //3.对其写入内容进行处理
            List<Equation_EVENT> equations = EquationUtils.Write2Equations(eva.WRITE_ITEM);
            if (equations != null && equations.Count > 0)
            {
                GlobalCachePool.write_event_dict.Add(eventNo, equations);
            }
        }

        public static void InitScanEvent(ScanEventEntity eva)
        {
            string eventNo = eva.EVENT_NO;
            if (string.IsNullOrEmpty(eventNo))
            {
                return;
            }
            GlobalCachePool.single_scanEvent_dict.Add(eventNo, eva);
            //2.对其触发条件进行处理
            List<EquationLinks_EVENT> equationLinks = EquationUtils.Cons2EquationLinks(eva.EVENT_CONS);
            if (equationLinks != null && equationLinks.Count > 0)
            {
                GlobalCachePool.links_event_dict.Add(eventNo, equationLinks);
            }
            //3.对其写入内容进行处理
            List<Equation_EVENT> equations = EquationUtils.Write2Equations(eva.WRITE_ITEM);
            if (equations != null && equations.Count > 0)
            {
                GlobalCachePool.write_event_dict.Add(eventNo, equations);
            }
        }


        public static void CollectReadItems(PlcReadEntity read)
        {
            string unitNo = read.UNIT_NO;
            string readNo = read.READ_NO;
            int dbBlock = read.DB_BLOCK;
            int beginAddr = read.BEGIN_ADR;
            int endAddr = read.END_ADR;
            //从相关设备ITEM点集合中获取信息
            if (GlobalCachePool.plcItems_dict.TryGetValue(unitNo, out List<PlcItemEntity> allItems))
            {
                List<PlcItemEntity> readItems = allItems.Where(item =>
                    unitNo.Equals(item.UNIT_NO) && item.ITEM_ADR >= beginAddr && item.ITEM_ADR <= endAddr
                    ).ToList();

                GlobalCachePool.plcItems_dict.Add(readNo, readItems);
            }
        }

        /// <summary>
        /// 为PLC_READ绑定相关信号点
        /// </summary>
        /// <param name="read"></param>
        public static void BindItemByRead(PlcReadEntity read)
        {
            string readNo = read.READ_NO;
            string unitNo = read.UNIT_NO;
            int dbBlock = read.DB_BLOCK;
            if (GlobalCachePool.plcItems_dict.TryGetValue(unitNo, out List<PlcItemEntity> items))
            {
                List<PlcItemEntity> itemByRead = new List<PlcItemEntity>();
                //同UNIT_NO且地址在PLC_READ之间的信号点
                itemByRead = items.Where(item => item.UNIT_NO.Equals(unitNo) && item.DB_BLOCK == dbBlock
                && item.ITEM_ADR >= read.BEGIN_ADR
                && item.ITEM_ADR <= read.END_ADR).ToList();
                GlobalCachePool.plcItems_dict.Add(readNo, itemByRead);

                if (itemByRead != null && itemByRead.Count > 0)
                {
                    List<string> eventItemNames = itemByRead.Where(item => !string.IsNullOrEmpty(item.EVENT_NO))
                        .Select(item => item.ITEM_NO)
                        .ToList();
                    GlobalCachePool.read_event_dict.Add(readNo, eventItemNames);
                }
            }
        }
        /// <summary>
        /// 对ITEM_NO相关的事件进行绑定
        /// </summary>
        /// <param name="item"></param>
        public static void BindEventByItem(PlcItemEntity item)
        {
            string unitNo = item.UNIT_NO;
            string itemCode = item.ITEM_CODE;
            string itemNo = item.ITEM_NO;
            string eventNo = item.EVENT_NO;
            if (string.IsNullOrEmpty(eventNo))
            {
                return;
            }
            //1.获取事件的信息并绑定
            if (GlobalCachePool.single_plcEvent_dict.TryGetValue(eventNo, out PlcEventEntity eva))
            {
                //1.1.将ITEM与事件缓存
                GlobalCachePool.item_event_dict.Add(itemNo, eva);
                string evaType = eva.EVENT_TYPE;
                //1.22.获取对应事件的触发链
                if (GlobalCachePool.links_event_dict.TryGetValue(eventNo, out List<EquationLinks_EVENT> links))
                {
                    if (SymbolConstants.EVENT_TYPE_I.Equals(evaType))
                    {
                        GlobalCachePool.links_event_dict.Add(itemNo, links);
                    }
                    else if (SymbolConstants.EVENT_TYPE_G.Equals(evaType))
                    {
                        //2.0.声明新的事件链用于存储变更后事件链
                        List<EquationLinks_EVENT> newLinks = new List<EquationLinks_EVENT>();
                        //2.1.将编号转换后记入缓存信息
                        foreach (EquationLinks_EVENT link in links)
                        {
                            List<Equation_EVENT> newEquations = new List<Equation_EVENT>();
                            foreach (Equation_EVENT equation in link.EQUATIONS)
                            {
                                string realItemNoL = MatchRealItemNo(unitNo, equation.LEFT_PREFIX, itemCode, equation.LEFT_MARK);
                                string realItemNoR = MatchRealItemNo(unitNo, equation.RIGHT_PREFIX, itemCode, equation.RIGHT_MARK);
                                Equation_EVENT newEquation = new Equation_EVENT
                                {
                                    LEFT_PREFIX = equation.LEFT_PREFIX,
                                    LEFT_MARK = realItemNoL,
                                    SYMBOL = equation.SYMBOL,
                                    RIGHT_PREFIX = equation.RIGHT_PREFIX,
                                    RIGHT_MARK = realItemNoR
                                };
                                newEquations.Add(newEquation);
                            }
                            EquationLinks_EVENT newLink = new EquationLinks_EVENT
                            {
                                RANK_NO = link.RANK_NO,
                                EQUATIONS = newEquations
                            };
                            newLinks.Add(newLink);
                        }
                        //2.3.将事件点相关的事件链加入缓存
                        GlobalCachePool.links_event_dict.Add(itemNo, newLinks);
                    }
                    else
                    {
                        //ERROR:事件类型不支持
                    }
                }
                //3.获取对应事件的写入内容
                if (GlobalCachePool.write_event_dict.TryGetValue(eventNo, out List<Equation_EVENT> equations))
                {
                    if (SymbolConstants.EVENT_TYPE_I.Equals(evaType))
                    {
                        GlobalCachePool.write_event_dict.Add(itemNo, equations);
                    }
                    else if (SymbolConstants.EVENT_TYPE_G.Equals(evaType))
                    {
                        //3.0.声明新的写入内容
                        List<Equation_EVENT> newWrites = new List<Equation_EVENT>();
                        foreach (Equation_EVENT equation in equations)
                        {
                            string realItemNoL = MatchRealItemNo(unitNo, equation.LEFT_PREFIX, itemCode, equation.LEFT_MARK);
                            Equation_EVENT newEquation = new Equation_EVENT
                            {
                                LEFT_PREFIX = equation.LEFT_PREFIX,
                                LEFT_MARK = realItemNoL,
                                SYMBOL = equation.SYMBOL,
                                RIGHT_PREFIX = equation.RIGHT_PREFIX,
                                RIGHT_MARK = equation.RIGHT_MARK
                            };
                            newWrites.Add(newEquation);
                        }
                        //3.1.将事件点相关的写入内容加入缓存
                        GlobalCachePool.write_event_dict.Add(itemNo, newWrites);
                    }
                    else
                    {
                        //ERROR:事件类型不支持
                    }
                }
            }
        }

        /// <summary>
        /// 根据编号与CODE获取真实的ITEM_NO
        /// </summary>
        /// <param name="unitNo"></param>
        /// <param name="prefix"></param>
        /// <param name="itemCode"></param>
        /// <param name="itemGrp"></param>
        /// <returns></returns>
        public static string MatchRealItemNo(string unitNo, string prefix, string itemCode, string itemGrp)
        {
            string itemNo = "";
            if (SymbolConstants.FLAG_PLC.Equals(prefix))
            {
                if (GlobalCachePool.plcItems_dict.TryGetValue(unitNo, out List<PlcItemEntity> items))
                {
                    PlcItemEntity entity = items.FirstOrDefault(item => item.ITEM_CODE.Equals(itemCode) && item.ITEM_GRP.Equals(itemGrp));
                    if (entity != null)
                    {
                        itemNo = entity.ITEM_NO;
                    }
                }
            }
            else if (SymbolConstants.FLAG_MEM.Equals(prefix))
            {
                if (GlobalCachePool.memItems_dict.TryGetValue(unitNo, out List<MemItemEntity> mems))
                {
                    MemItemEntity memEntity = mems.FirstOrDefault(item => item.ITEM_CODE.Equals(itemCode) && item.ITEM_GRP.Equals(itemGrp));
                    if (memEntity != null)
                    {
                        itemNo = memEntity.ITEM_NO;
                    }
                }
            }
            else
            {
                itemNo = itemGrp;
            }
            return itemNo;
        }
    }
}
